package com.ws.client.controller;

import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * 封装了XML转换成object，object转换成XML的代码
 *
 * @author Steven
 *
 */
public class XmlUtils {
    private Marshaller installMarshaller(Class clz){
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(clz);

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.toString());
            //是否省略xml头信息，默认不省略（false）
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                @Override
                public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                    if (namespaceUri.equals("http://www.lzrabbit.cn")) return "abc";
                    if (namespaceUri.contains("http://www.cnblogs.com")) return "blog";
                    return suggestion;
                }
            });
            return marshaller;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将对象直接转换成String类型的 XML输出
     *
     * @param obj
     * @return
     */
    public static String convertToXml(Object obj) {
        // 创建输出流
        StringWriter sw = new StringWriter();
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.toString());
            //是否省略xml头信息，默认不省略（false）
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            // 将对象转换成输出流形式的xml
            marshaller.marshal(obj, sw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return sw.toString();
    }

    /**
     * 将对象根据路径转换成xml文件
     *
     * @param obj
     * @param path
     * @return
     */
    public static void convertToXml(Object obj, String path) {
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.toString());
            //是否省略xml头信息，默认不省略（false）
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);

            marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                @Override
                public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                    if (namespaceUri.equals("http://www.lzrabbit.cn")) return "";
                    if (namespaceUri.contains("http://www.cnblogs.com")) return "blog";
                    return suggestion;
                }
            });
            // 将对象转换成输出流形式的xml
            // 创建输出流
            FileWriter fw = null;
            try {
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            marshaller.marshal(obj, fw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    /**
     * 将String类型的xml转换成对象
     */
    public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            // 进行将Xml转成对象的核心接口
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader sr = new StringReader(xmlStr);
            xmlObject = unmarshaller.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

    @SuppressWarnings("unchecked")
    /**
     * 将file类型的xml转换成对象
     */
    public static Object convertXmlFileToObject(Class clazz, String xmlPath) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            FileReader fr = null;
            try {
                fr = new FileReader(xmlPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            xmlObject = unmarshaller.unmarshal(fr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xmlObject;
    }

    /**
     * @Description bean转成xml
     * @Param [t]
     * @Return java.lang.String
     */
    public static <T> String beanToXml(T t) {
        String xml=null;
        try {
            //获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass());
            //创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象。
            Marshaller m = context.createMarshaller();
            // 格式化xml输出的格式
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            m.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.toString());
            //是否省略xml头信息，默认不省略（false）
            //m.setProperty(Marshaller.JAXB_FRAGMENT, true);
            //创建一个StringWriter流将接收到的对象流写入xml字符串
            StringWriter sw = new StringWriter();
            //调用marshal方法进行转换
            m.marshal(t,sw);
            //将读取到的StringWriter流转成String返回
            xml = sw.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xml;
    }

    /**
     * @Description bean转成xml(泛型使用)
     * @Param [t]
     * @Return java.lang.String
     */
    public static <T> String beanToXml(T t, Class c) {
        String xml=null;
        try {
            //获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass(),c);
            //创建一个可以用来将 java 内容树转换为 XML 数据的 Marshaller 对象。
            Marshaller m = context.createMarshaller();
            // 格式化xml输出的格式
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            //设置编码（默认编码就是utf-8）
            m.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.toString());
            //是否省略xml头信息，默认不省略（false）
            m.setProperty(Marshaller.JAXB_FRAGMENT, true);
            //创建一个StringWriter流将接收到的对象流写入xml字符串
            StringWriter sw = new StringWriter();
            //调用marshal方法进行转换
            m.marshal(t,sw);
            //将读取到的StringWriter流转成String返回
            xml= sw.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return xml;
    }

    /**
     * @Description xml 转成 bean
     * @Param [xml, t]
     * @Return T
     */
    public static <T> T xmlToBean(String xml, T t) {
        try {
            ////获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass());
            //创建一个可以用来将 XML 数据转换为 java 内容树的 Unmarshaller 对象。
            Unmarshaller um = context.createUnmarshaller();
            //创建一个StringReader将xml报文转成流
            StringReader sr = new StringReader(xml);
            //调用unmarshal进行转换，并把Object类型强转为调用者的类型
            t = (T) um.unmarshal(sr);

        } catch (JAXBException e) {
            e.printStackTrace();
        }
        //将对象返回给调用者
        return t;
    }

    /**
     * @Description xml 转成 bean(泛型使用)
     * @Param [xml, t]
     * @Return T
     */
    public static <T> T xmlToBean(String xml, T t, Class c) {
        try {
            ////获得 JAXBContext 类的新实例。参数为类的地址
            JAXBContext context = JAXBContext.newInstance(t.getClass(),c);
            //创建一个可以用来将 XML 数据转换为 java 内容树的 Unmarshaller 对象。
            Unmarshaller um = context.createUnmarshaller();
            //创建一个StringReader将xml报文转成流
            StringReader sr = new StringReader(xml);
            //调用unmarshal进行转换，并把Object类型强转为调用者的类型
            t = (T) um.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        //将对象返回给调用者
        return t;
    }



}